#include <iostream>
#include "HomeScreenManager.h"
#include "Protocol/ProtocolApi.h"
#include "ConfigApi.h"
#include "ScreenMirrorStream.h"
#include "DiskController.h"
#include "errorCode.h"
#include "Util/logc.h"
#include "Util/File.h"
#include "Gui/GuiDisplay.h"

using namespace Protocol;
using namespace ConfigApi;


bool isImageFile(const std::string& filename) {
    std::string extension = filename.substr(filename.find_last_of('.') + 1);
    std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
    return extension == "jpg" || extension == "jpeg"  || extension == "png";
}


HomeScreenManager::Ptr HomeScreenManager::Instance(){
    static HomeScreenManager::Ptr manager = std::make_shared<HomeScreenManager>();
    return manager;
}

HomeScreenManager::HomeScreenManager(){
    registRPC();
}

HomeScreenManager::~HomeScreenManager(){

}

void HomeScreenManager::registRPC(){
    tracef("AuditoryworksRegistRequestRpcEx  CreateHomeScreen");
    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("CreateHomeScreen", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return createHomeScreen(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("GetHomeScreen", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return getHomeScreen(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("StopHomeScreen", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return stopHomeScreen(req_params, res_result, errinfo, errorCode);
        });
}

static std::string extractFilenameFromUrl(const std::string& url) {
    std::string filename = "";
    size_t pos = url.find_last_of('/');

    if (pos != std::string::npos) {
        filename = url.substr(pos + 1);
    }

    return filename;
}


bool HomeScreenManager::getHomeScreen(const Json::Value& req_params, Json::Value& res_result, 
            std::string& errinfo, int& errorCode){
    Json::Value table = Json::nullValue;    
    if(!IConfigInterface::GetInstance()->Get("homeScreen", table)){
        warnf("not found homeScreen  config");
    }else{
        res_result = table;
    }

    return true;
}

bool HomeScreenManager::createHomeScreen(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    tracef("  request createHomeScreen  come");
    if(Media::ScreenMirrorStream::instance()->getShareScreenStatus())
    {
        errinfo = "The device is displaying screen mirroring information, please try again later.";
        errorCode = Media::ScreenPlaying;
        errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
		return false;        
    }
    
    if(req_params.empty()){ //reset homescreen
        Json::Value homeScreen;
        homeScreen["homeScreenImage"] = "";
        ConfigApi::IConfigInterface::GetInstance()->Set("homeScreen",
            homeScreen, ConfigApi::ConfigOptions::ConfigOptionSaveAll);
        
        Media::GuiDisplay::Instance()->ReloadHomeScreen();
        return true;
    }

    //parse homeScreen
    std::string homeScreenImage;
    std::string homeScreenFilename;
    std::string homeScreenFilePath;
    if(req_params.isMember("homeScreenImage")){
        homeScreenImage = req_params["homeScreenImage"].asString();
    }else{
        errinfo = "not found homeScreenImage";
        errorCode = Media::IllegalParameter;
        errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
		return false;
    }

    int homeScreenImageSize = 0;
    if(req_params.isMember("homeScreenImageSize")){
        homeScreenImageSize = req_params["homeScreenImageSize"].asInt();
    }

    //get storage path
    std::string storage_path;
    if(!DiskController::instance()->getRealTimeRootPath(storage_path)){
        errorCode = Media::InternalError;
        errinfo = "not found storage path";
        errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
		return false;
    }

    auto downloadFileLam = [](const std::string& file_path, const std::string& url){
            int download_progress = 0;
            Protocol::IProtocolInterface::GetInstance()->HttpDownloadFile(url, file_path, 
                [&download_progress](const Fdt::SockException &ex){
                    if(ex.getErrCode() != Fdt::Err_success){
                        errorf("download  faild, errinfo=%s\n", ex.what());
                        download_progress = -1;
                    }else{
                        download_progress = 100;
                    }
                }, download_progress);
            
            while(download_progress >= 0 && download_progress < 100){
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }

            if(download_progress != 100){
                return false;
            }
            return true;
    };

    //if is http, to download it

    if(homeScreenImage.find("http") != std::string::npos){
        homeScreenFilename= extractFilenameFromUrl(homeScreenImage);
        homeScreenFilePath = storage_path + "/" + homeScreenFilename;

        if(!isImageFile(homeScreenFilename)){
            errinfo = "homeScreenImage file format must jpg or png";
            errorCode = Media::IllegalFileFormat;
            errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
            return false;
        }

        if(Fdt::File::fileExist(homeScreenFilePath.c_str())){
            Fdt::File::delete_file(homeScreenFilePath.c_str());
            m_index++;
            homeScreenFilename = std::to_string(m_index) + "_" + homeScreenFilename;
            homeScreenFilePath = storage_path + "/" + homeScreenFilename;
        }

        if(!downloadFileLam(homeScreenFilePath, homeScreenImage)){
            errinfo = "download homeScreenImage faild";
            errorCode = Media::InternalError;
            errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
            return false;
        }
    }else{
        //check local file exist
        homeScreenFilename = extractFilenameFromUrl(homeScreenImage);
        if(homeScreenFilename.empty()){
            homeScreenFilename = homeScreenImage;
        }

        homeScreenFilePath = storage_path + "/" + homeScreenFilename;

        tracef("home screen  file path %s\n", homeScreenFilePath.c_str());
        if(!Fdt::File::fileExist(homeScreenFilePath.c_str()) || 
            Fdt::File::is_dir(homeScreenFilePath.c_str())){
            errinfo = "not found homeScreen file";
            errorCode = Media::InternalError;
            errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
            return false;
        }
    }

    if(homeScreenImageSize == 0){
        homeScreenImageSize = Fdt::File::fileSize(homeScreenFilePath.c_str());
    }

    //parse background
    std::string backgroundImage;
    std::string backgroundFilename;
    std::string backgroundFilePath;
    int backgroundImageSize = 0;
    if(req_params.isMember("backgroundImage")){
        backgroundImage = req_params["backgroundImage"].asString();
        if(req_params.isMember("backgroundImageSize")){
            backgroundImageSize = req_params["backgroundImageSize"].asInt();
        }

        //if is http, to download it
        if(backgroundImage.find("http") != std::string::npos){
            backgroundFilename = extractFilenameFromUrl(backgroundImage);
            backgroundFilePath = storage_path + "/" + backgroundFilename;
            if(!downloadFileLam(backgroundFilePath, backgroundImage)){
                errinfo = "download backgroundImage faild";
                errorCode = Media::InternalError;
                errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
                return false;
            }

        }else{
            //check local file exist
            backgroundFilename = extractFilenameFromUrl(backgroundImage);
            if(backgroundFilename.empty()){
                backgroundFilename = backgroundImage;
            }
            backgroundFilePath = storage_path + "/" + backgroundFilename;
            if(!Fdt::File::fileExist(backgroundFilePath.c_str()) || 
                Fdt::File::is_dir(backgroundFilePath.c_str())){
                errinfo = "not found background file";
                errorCode = Media::InternalError;
                errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
                return false;
            }
        }

        if(backgroundImageSize == 0){
            backgroundImageSize = Fdt::File::fileSize(backgroundFilePath.c_str());
        }
    }

    //parse textInfo
    Json::Value textInfo;
    if(req_params.isMember("textInfo")){
        textInfo = req_params["textInfo"];
    }

    m_homeScreen = std::make_shared<HomeScreen>(homeScreenFilePath, homeScreenImageSize, 
        backgroundFilePath, backgroundImageSize, textInfo);

    Json::Value homeScreen;
    if(!textInfo.empty()){
        homeScreen["textInfo"] = textInfo;
    }
    homeScreen["homeScreenImage"] = homeScreenFilePath;
    homeScreen["homeScreenImageSize"] = homeScreenImageSize;
    if(!backgroundFilePath.empty()){
        homeScreen["backgroundImage"] = backgroundFilePath;
        homeScreen["backgroundImageSize"] = backgroundImageSize;
    }

    ConfigApi::IConfigInterface::GetInstance()->Set("homeScreen",
         homeScreen, ConfigApi::ConfigOptions::ConfigOptionSaveAll);
    
    Media::GuiDisplay::Instance()->ReloadHomeScreen();

    return true;
}


bool HomeScreenManager::stopHomeScreen(const Json::Value& req_params, Json::Value& res_result, 
            std::string& errinfo, int& errorCode){
    
    tracef("  request stopHomeScreen  come");
    if(Media::ScreenMirrorStream::instance()->getShareScreenStatus())
    {
        errinfo = "The device is displaying screen mirroring information, please try again later.";
        errorCode = Media::ScreenPlaying;
        errorf("createHomeScreen faild, errinfo=%s\n", errinfo.c_str());
		return false;        
    }

    Json::Value homeScreen;
    homeScreen["homeScreenImage"] = "";
    ConfigApi::IConfigInterface::GetInstance()->Set("homeScreen",
        homeScreen, ConfigApi::ConfigOptions::ConfigOptionSaveAll);
    
    Media::GuiDisplay::Instance()->ReloadHomeScreen();

    return true;
}